﻿using FDStudio.Core.Config;
using FDStudio.Core.Entities;
using FDStudio.Core.Entities.Enums;
using FDStudio.Core.Entities.Query;
using FDStudio.Core.Exceptions;
using FDStudio.Core.Extensions;
using FDStudio.Core.Generates;
using FDStudio.Core.Runtime;
using FDStudio.Core.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace FDStudio.Core.Repositories
{
    /*
     CreatedOn: 2018-01-26
     CreatedBy: Jackie Lee(天宇遊龍)
     */
    /// <summary>
    /// 基本只写仓储上下文
    /// </summary>
    public abstract class DefaultWriteOnlyRepositoryContext : BaseContext, IWriteOnlyRepositoryContext
    {
        /// <summary>
        /// 模型生成器
        /// </summary>
        protected IModelGenerator modelGenerator => RuntimeContext.Current.Container.Resove<IModelGenerator>();

        /// <summary>
        /// 数据库类型
        /// </summary>
        public abstract DatabaseType DatabaseType { get; }

        /// <summary>
        /// 连接字符串
        /// </summary>
        public string ConnectionString { get; private set; }

        /// <summary>
        /// 数据连接配置
        /// </summary>
        public IDbConnectionString DbConnectionString { get; private set; }

        /// <summary>
        /// 当插入数据时，获取新插入值自增列
        /// </summary>
        public abstract string AddedIDString { get; }
        
        public DefaultWriteOnlyRepositoryContext()
        {
            var configName = RuntimeContext.Current.Container.Resove<IWriteOnlyContextOptions>()?.ConnConfigName;
            Switch(DatabaseType, configName);
        }

        /// <summary>
        /// 切换
        /// </summary>
        /// <param name="databaseType"></param>
        /// <param name="name"></param>
        public void Switch(DatabaseType databaseType, string name = "")
        {
            //var connConfigs = RuntimeContext.Current.Container.ResoveAll<IDbConnectionString>();
            //if (connConfigs == null || connConfigs.Count() == 0)
            //    throw new DbConnectionConfigException("当前上下文中不存在数据库连接类型");
            //var config = connConfigs.FirstOrDefault(c => c.DatabaseType == DatabaseType && (name.IsNullOrEmpty() ? true : c.Name == name));
            //if (config == null)
            //    throw new DbConnectionConfigException($"当前上下文中不存在{DatabaseType}类型数据库连接类型");
            //ConnectionString = config.ConnectionString;
            //DbConnectionString = config;
            DbConnectionString = DbConnHelper.GetConnectionConfig(databaseType, DatabaseOperType.WriteOnly, name);
            ConnectionString = DbConnectionString.ConnectionString;
        }

        private IDbCommand CreateCommand(IDbConnection connection)
        {
            return connection.CreateCommand();
        }

        public virtual bool Add<T>(T model) where T : class, IEntity
        {
            using (var connection = CreateConnection())
            {
                var sql = modelGenerator.InsertString(model, out IDictionary<string, object> parameters);
                bool res = ExecuteNonQuery(connection, sql, parameters, CommandType.Text) > 0;
                if (res && !AddedIDString.IsNullOrEmpty())
                {
                    var obj = GetCommand(connection, AddedIDString, CommandType.Text).ExecuteScalar();
                    model.Id = obj.ToLong();
                }
                return res;
            }
        }

        private int ExecuteNonQuery(IDbConnection connection, string sql, object parameter, CommandType commandType)
        {
            return GetCommand(connection, sql, parameter, commandType).ExecuteNonQuery();
        }

        public virtual int ExecuteNonQuery(string sql, object parameter, CommandType commandType = CommandType.Text)
        {
            using (var connection = CreateConnection())
            {
                var cmd = GetCommand(connection, sql, parameter, commandType);
                return cmd.ExecuteNonQuery();
            }
        }

        private IDbCommand GetCommand(IDbConnection connection, string sql, CommandType commandType)
        {
            if (connection.State != ConnectionState.Open)
            {
                connection.Open();
            }
            var cmd = CreateCommand(connection);
            cmd.CommandText = sql;
            cmd.CommandType = commandType;
            return cmd;
        }

        private IDbCommand GetCommand(IDbConnection connection, string sql, object param, CommandType commandType)
        {
            var cmd = GetCommand(connection, sql, commandType);
            SqlCommHelper.AddParameter(cmd, param);
            return cmd;
        }

        public virtual bool Update<T>(T model) where T : class, IEntity
        {
            using (var connection = CreateConnection())
            {
                var sql = modelGenerator.UpdateString<T>(t => t.Id == model.Id);
                return ExecuteNonQuery(connection, sql, model, CommandType.Text) > 0;
            }
        }

        public virtual bool Delete<T>(T model) where T : class, IEntity
        {
            return Delete<T>(t => t.Id == model.Id);
        }

        public virtual bool Delete<T>(Expression<Func<T, bool>> condition) where T : class, IEntity
        {
            using (var connection = CreateConnection())
            {
                var sql = modelGenerator.DeleteString(condition);
                return ExecuteNonQuery(connection, sql, null, CommandType.Text) > 0;
            }
        }

        public virtual void Dispose()
        {
            DisposeTransaction(true);
        }

    }
}
